#include <stdio.h>
#include "database_interface.h"
#include "testcode.h"
#include "atomic_lib.h"

const int kl = 10;
const int vl = 100;

void test0() {
	int id, r;
	id = db_create_db(kl, vl);
	printf("Create database id = %d\n", id);
	r = db_save(id, "test.lzdb");
	printf("Save database id = %d retcode = %d\n", id, r);
	r = db_close_db(id);
	printf("Close database id = %d retcode = %d\n", id, r);
}

void test1() {
	int id0, id1, r;
	id0 = db_load("test.lzdb");
	printf("Load database id = %d\n", id0);
	id1 = db_load("test.lzdb");
	printf("Load database id = %d\n", id1);
	r = db_close_db(id0);
	printf("Close database id = %d retcode = %d\n", id0, r);
	r = db_close_db(id1);
	printf("Close database id = %d retcode = %d\n", id1, r);
}

void test2() {
	int id, r, i;
	id = db_load("test.lzdb");
	char a[10], b[100];
	for (i = 0; i < 10; i++) a[i] = '1';
	for (i = 0; i < 100; i++) b[i] = '2';
	struct database_item tmp;
	tmp.key = a;
	tmp.value = (void *) b;
	(void) tmp;
	printf("Start to insert\n");
	r = db_insert_data(id, &tmp);
	printf("Insert data into database id = %d retcode = %d\n", id, r);
	a[6] = '2';
	r = db_insert_data(id, &tmp);
	printf("Insert data into database id = %d retcode = %d\n", id, r);
	sleep(1);
	struct database_item_list *ret, *del;
	printf("Start to query\n");
	fflush(stdout);
	r = db_query_data(id, all_item, &ret);
	del = ret;
	printf("Find all items in database %p retcode = %d\n", ret, r);
	int tot = 0;
	while (ret) {
		printf("item %d:\n", tot);
		tot++;
		printf("key = ");
		for (i = 0; i < 10; i++) printf("%c", ret->dbi.key[i]);
		printf("\nvalue = ");
		for (i = 0; i < 100; i++) printf("%c", *((char *) (ret->dbi.value) + i));
		printf("\n");
		ret = ret->next;
	}
	printf("Find end, start to delete item list\n");
	delete_database_item_list(del);
	printf("Delete end, start to close database\n");
	r = db_close_db(id);
	printf("Close database id = %d retcode = %d\n", id, r);
}

inline void int_to_str(unsigned x, char *tmp, int bytes) {
	int i;
	for (i = 0; i < bytes; i++)
		tmp[i] = (x >> ((bytes - i - 1) * 8)) & 255;
}

inline int str_to_int(const char *tmp, int bytes) {
	int ret = 0, i;
	for (i = 0; i < bytes; i++)
		ret = (ret << 8) + (((unsigned) tmp[i]) & 255);
	return ret;
}

void insert_speed_test() {
	int n = 1 << 24;
	(void) n;
	int id = db_create_db(3, 3);
	struct database_item dbi;
	dbi.key = (char *) malloc(3);
	dbi.value = malloc(3);
	int i, r;
	clock_t cur = clock();
	for (i = 0; i < n; i++) {
		/*
		if (i % 100000 == 0)
			fprintf(stderr, "insert %d\n", i);
		*/
		int_to_str((unsigned) i, dbi.key, 3);
		int_to_str((unsigned) i, (char *) dbi.value, 3);
		r = db_insert_data(id, &dbi);
	}
	clock_t now = clock();
	printf("Time Cost: %.3f\n", (double) (now - cur) / CLOCKS_PER_SEC);
	//sleep(3);
	db_save(id, "insert_data.lzdb");
	r = db_close_db(id);
	printf("Close database id = %d retcode = %d\n", id, r);
	free(dbi.key);
	free(dbi.value);
}

struct database_item dbi;

int32_t delete_check(struct database_item *tdbi) {
	//return 1;
	return key_strcmp(tdbi->key, dbi.key, 3) == 0;
}

void delete_speed_test() {
	int n = 1 << 24;
	(void) n;
	int id = db_load("insert_data.lzdb");
	fprintf(stderr, "load ok\n");
	dbi.key = (char *) malloc(3);
	dbi.value = malloc(3);
	int i, r;
	clock_t cur = clock();
	for (i = 0; i < n; i++) {

		if (i % 100000 == 0)
			fprintf(stderr, "delete %d\n", i);

		int_to_str((unsigned) i, dbi.key, 3);
		int_to_str((unsigned) i, (char *) dbi.value, 3);
		r = db_delete_data(id, delete_check);
	}
	clock_t now = clock();
	printf("Time Cost: %.3f\n", (double) (now - cur) / CLOCKS_PER_SEC);
	//sleep(3);
	db_save(id, "delete_data.lzdb");
	r = db_close_db(id);
	printf("Close database id = %d retcode = %d\n", id, r);
	free(dbi.key);
	free(dbi.value);
}

int32_t clear_check(struct database_item *tdbi) {
	(void) tdbi;
	return 1;
}

void clear_speed_test() {
	int n = 1 << 24, r;
	(void) n;
	int id = db_load("insert_data.lzdb");
	fprintf(stderr, "load ok\n");
	clock_t cur = clock();
	db_delete_data(id, clear_check);
	clock_t now = clock();
	printf("Time Cost: %.3f\n", (double) (now - cur) / CLOCKS_PER_SEC);
	db_save(id, "clear_data.lzdb");
	r = db_close_db(id);
	printf("Close database id = %d retcode = %d\n", id, r);
}

void search_speed_test() {
	int n = 1 << 24;
	(void) n;
	int id = db_load("insert_data.lzdb");
	fprintf(stderr, "load ok\n");
	clock_t cur = clock();
	int i;
	struct database_keypair tmp;
	tmp.l = malloc(3);
	tmp.r = malloc(3);
	int l = 0, r;
	for (i = 0; i < n; i++) {
		l = (l * 17 + 3) & (n - 1);
		r = l + 3;
		if (r >= n) r = n - 1;
		int_to_str(l, tmp.l, 3);
		int_to_str(r, tmp.r, 3);
		struct database_item_list *dbil;
		if (i % 100000 == 0)
			fprintf(stderr, "query %d\n", i);
		assert(db_query_data_from_key(id, &tmp, &dbil) == 0);
		delete_database_item_list(dbil);
	}

	clock_t now = clock();
	printf("Time Cost: %.3f\n", (double) (now - cur) / CLOCKS_PER_SEC);
	free(tmp.l);
	free(tmp.r);
	r = db_close_db(id);
	printf("Close database id = %d retcode = %d\n", id, r);
}

int main() {
	printf("%s\n", "Hello, World!");
	db_manage_init();

#ifdef USER_CHAOLI
	search_speed_test();
	//delete_speed_test();
	//insert_speed_test();
#else
	test_database();
#endif

	printf("End successfully\n");
	return 0;
}